package multi;

import java.util.Calendar;
import java.util.Iterator;
import java.util.Set;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.CommandResult;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoOptions;
import com.mongodb.util.JSON;

public class SpatialMultiTestMongo implements Runnable {
	static Mongo m = null;
	static DB db = null;
	static DBCollection coll = null;

	public void run() {
		System.out.println("Started: " + Thread.currentThread().getName());
		try
		{
			if (m == null)
			{
				m = new Mongo("localhost");
				db = m.getDB("mydb");
				coll = db.getCollection("people");
				coll.ensureIndex((DBObject) JSON.parse("{ 'loc' : '2d' }"));	
				MongoOptions mOptions = new MongoOptions();
				//System.out.println("connectionsPerHost: " + mOptions.connectionsPerHost);
				//System.out.println("threadsAllowedToBlockForConnectionMultiplier: " + mOptions.threadsAllowedToBlockForConnectionMultiplier);
				mOptions.threadsAllowedToBlockForConnectionMultiplier=15;
			}
			
			searchWithNearSphere();
			searchWithGeoNear();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}		
		
		System.out.println("Done: " + Thread.currentThread().getName());
	} 

	static void searchWithNearSphere() {
		System.out.println("Method: searchWithNearSphere()");
		// 1 radian = 3959 miles (6371 km).
		// So, 100 miles = 100/3959 = 0.0253 radians.
		// So, 1000 miles = 1000/3959 = 0.253 radians.
		// Must use long/lat format, and not lat/long.
		// Valid bounds for latitude is -90/90.
		// Valid bounds for longitude is -180/180

		
		String query = "{'$nearSphere' : [ " + Constants.LON + ", " + Constants.LAT + " ] , '$maxDistance' : " + Constants.RADIUS_RADIANS + "}";
		System.out.println("Query to use: " + query);

		for (int i = 0; i < Constants.NO_OF_LOOPS_PER_THREAD; i++) {
			long startTime = Calendar.getInstance().getTimeInMillis();
			DBCursor cur = coll.find(new BasicDBObject("loc", JSON.parse(query))).limit(Constants.RESULT_ROWS_LIMIT);
			long timeTaken = Calendar.getInstance().getTimeInMillis() - startTime;
			Constants.addTotalTime(timeTaken);
			System.out.println("Total Time Taken for 'searchWithNearSphere(milliseconds): " + timeTaken);

			System.out.println("Total Documents Found - cur.count(): " + cur.count());
			System.out.println("Total Documents Found - cur.length(): " + cur.length());
			System.out.println("Total Documents Found - cur.size(): " + cur.size());			
		}

		/*
		 * while (cur.hasNext()) { System.out.println(cur.next()); }
		 * 
		 * System.out.println("Total Documents Found: " + cur.size());
		 */

	}
	
	private void searchWithGeoNear() {
		System.out.println("Method: searchWithGeoNear()");
		BasicDBObject cmd = new BasicDBObject();
		cmd.put("geoNear", "people");
		double coord[] = { Constants.LON, Constants.LAT };
		cmd.put("near", coord);
		cmd.put("num", Constants.RESULT_ROWS_LIMIT);//Max Rows to Returns
		cmd.put("maxDistance", Constants.RADIUS_RADIANS); //Radius Search. In Radians.
		cmd.put("spherical", true);

		for (int i = 0; i < Constants.NO_OF_LOOPS_PER_THREAD; i++) {
			long startTime = Calendar.getInstance().getTimeInMillis();
			CommandResult r = db.command(cmd);
			long timeTaken = Calendar.getInstance().getTimeInMillis() - startTime;
			Constants.addTotalTime(timeTaken);
			System.out.println("Total Time Taken for 'searchWithGeoNear(milliseconds): " + timeTaken);
			System.out.println(r.ok());
			System.out.println(r.getErrorMessage());
			// System.out.println(r.toString());
			// print(r);//Print all the returned data.

			com.mongodb.BasicDBList resultsBasicDBList = (BasicDBList) r.get("results");
			System.out.println("Total Results: " + resultsBasicDBList.size());

			// System.out.println("Results: " + resultsBasicDBList); //This will
			// print the value of 'results' key.

			// print(resultsBasicDBList);//This will print individual values.
		}
	}

	public static void print(DBObject doc) {
		Set<String> allKeys = doc.keySet();
		Iterator<String> it = allKeys.iterator();
		while (it.hasNext()) {

			Object o = it.next();
			String temp = (String) o; // it.next();
			// System.out.println("K CLASS: " + o);
			// System.out.println("V CLASS: " + doc.get(temp).getClass());
			System.out.print(temp + "-");

			if (doc.get(temp) instanceof BasicDBObject) {
				System.out.println("\n");
				print((DBObject) doc.get(temp));
			} else {
				System.out.println(doc.get(temp));
				if (temp.toString().equalsIgnoreCase("loc"))
					System.out.println("-------------");
			}
		}
	}
} // end class
